home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / install / chlib-1.000 / chlib-1 / chlib / chlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-16  |  4.9 KB  |  204 lines

  1. /*
  2.  * Copyright 1993  David Engel
  3.  *
  4.  * This program may be used for any purpose as long as this
  5.  * copyright notice is kept.
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdarg.h>
  11. #include <getopt.h>
  12. #include <unistd.h>
  13. #include <errno.h>
  14. #include <a.out.h>
  15. #include <sys/stat.h>
  16.  
  17. #define VERSION "1.0 (8/16/93)"
  18.  
  19. char *prog = "chlib";
  20.  
  21. volatile void error(char *fmt, ...)
  22. {
  23.     va_list ap;
  24.  
  25.     fprintf(stderr, "%s: ", prog);
  26.  
  27.     va_start(ap, fmt);
  28.     vfprintf(stderr, fmt, ap);
  29.     va_end(ap);
  30.  
  31.     fprintf(stderr, "\n");
  32.  
  33.     exit(1);
  34. }
  35.  
  36. /* read relevant info about a shared library. */
  37.  
  38. int libinfo(int must, char *name, unsigned *addr, unsigned *vers,
  39.         struct stat *stbuf)
  40. {
  41.     FILE *file;
  42.     struct exec exec;
  43.  
  44.     /* see if we can stat it */
  45.     if (stat(name, stbuf))
  46.     {
  47.     /* if must exist flag is set, it's an error */
  48.     if (must)
  49.         error("can't stat %s (%s)", name, strerror(errno));
  50.     else
  51.         return 0;
  52.     }
  53.  
  54.     /* try to open it */
  55.     if ((file = fopen(name, "rb")) == NULL)
  56.     error("can't open %s (%s)", name, strerror(errno));
  57.  
  58.     /* and read the exec header */
  59.     if (fread(&exec, sizeof exec, 1, file) != 1)
  60.     error("can't read exec header from %s", name);
  61.  
  62.     /* shared libs must be ZMAGIC */
  63.     if (N_MAGIC(exec) != ZMAGIC || !exec.a_entry)
  64.     error("%s is not a shared library", name);
  65.  
  66.     *addr = exec.a_entry;
  67.  
  68.     /* now seek to where the version number */
  69.     if (fseek(file, N_TXTOFF(exec), SEEK_SET))
  70.     error("can't seek to version in %s", name);
  71.  
  72.     /* and try to read the version number */
  73.     if (fread(vers, sizeof *vers, 1, file) != 1)
  74.     error("can't read version number from %s", name);
  75.  
  76.     /* we're done with the file */
  77.     fclose(file);
  78.     
  79.     return 1;
  80. }
  81.  
  82. int main(int argc, char **argv)
  83. {
  84.     int c;
  85.     int force = 0;
  86.     char *newlib;
  87.     char *linkdir;
  88.     char *cp, *cp2;
  89.     char linkname[1024];
  90.     unsigned newaddr, oldaddr;
  91.     unsigned newvers, oldvers;
  92.     struct stat newstat, oldstat;
  93.     struct stat linkstat;
  94.  
  95.     prog = argv[0];
  96.     opterr = 0;
  97.  
  98.     /* parse command-line options */
  99.     while ((c = getopt(argc, argv, "vf")) != EOF)
  100.     switch (c)
  101.     {
  102.     case 'v':
  103.         printf("%s: version %s\n", argv[0], VERSION);
  104.         exit(0);
  105.     case 'f':
  106.         force = 1;
  107.         break;
  108.     default:
  109.         error("invalid option -%c", optopt);
  110.     }
  111.  
  112.     /* must be either one or two args left */
  113.     if (argc - optind < 1 || argc - optind > 2)
  114.     {
  115.     fprintf(stderr, "usage: %s [-vf] newlib [linkdir]\n", argv[0]);
  116.     exit(1);
  117.     }
  118.  
  119.     /* pick off newlib argument */
  120.     newlib = argv[optind];
  121.  
  122.     /* pick off linkdir argumnet or use default */
  123.     if (argc - optind > 1)
  124.     {
  125.     linkdir = argv[optind+1];
  126.  
  127.     /* strip trailing slashes from linkdir */
  128.     for (cp = linkdir+strlen(linkdir)-1;
  129.          cp > linkdir && *cp == '/'; cp--)
  130.         ;
  131.     cp[1] = '\0';
  132.     }
  133.     else
  134.     linkdir = "/lib";
  135.  
  136.     /* make sure linkdir is a directory */
  137.     if (stat(linkdir, &linkstat) || !S_ISDIR(linkstat.st_mode))
  138.     error("%s is not a directory", linkdir);
  139.  
  140.     /* check if newlib is a valid shared library name */
  141.     cp = strrchr(newlib, '/');
  142.     if (cp)
  143.     cp++;
  144.     else
  145.     cp = newlib;
  146.     cp2 = strstr(cp, ".so.");
  147.     if (cp2)
  148.     cp2 = strchr(cp2 + 4, '.');
  149.     if (!cp2)
  150.     error("%s is not a shared library name", newlib);
  151.  
  152.     /* build the shared library link name */
  153.     sprintf(linkname, "%s/", linkdir);
  154.     strncat(linkname, cp, cp2 - cp);
  155.  
  156.     /* check for for relative newlib and absolute linkdir */
  157.     if (*newlib != '/' && *linkdir == '/')
  158.     {
  159.     if (strcmp(linkdir, getcwd(NULL, 0)) != 0)
  160.         error("current directory is not %s", linkdir);
  161.     }
  162.  
  163.     /* read info about the new shared library */
  164.     libinfo(1, newlib, &newaddr, &newvers, &newstat);
  165.  
  166.     /* try to read info about any existing library */
  167.     if (libinfo(0, linkname, &oldaddr, &oldvers, &oldstat))
  168.     {
  169.     /* see if the link is already set to newlib */
  170.     if (newstat.st_dev == oldstat.st_dev &&
  171.         newstat.st_ino == oldstat.st_ino)
  172.         error("%s already points to %s", linkname, newlib);
  173.  
  174.     /* make sure the load addresses match */
  175.     if (newaddr != oldaddr)
  176.         error("load address for %s (0x%x) does not match\n"
  177.           "\tthat of current %s (0x%x)", newlib, newaddr,
  178.           linkname, oldaddr);
  179.  
  180.     /* make sure the major version numbers match */
  181.     if ((0xffff0000 & newvers) != (0xffff0000 & oldvers))
  182.         error("major version for %s (%d) does not match\n"
  183.           "\tthat of current %s (%d)", newlib, newvers >> 16,
  184.           linkname, oldvers >> 16);
  185.  
  186.     /* make sure the new minor version number is greater */
  187.     if (!force && (0x0000ffff & newvers) <= (0x0000ffff & oldvers))
  188.         error("minor version of %s (%d) is not greater than\n"
  189.           "\tthat of current %s (%d)", newlib, newvers & 0xffff,
  190.           linkname, oldvers & 0xffff);
  191.     }
  192.  
  193.     /* remove any existing link */
  194.     if (!lstat(linkname, &oldstat) && remove(linkname))
  195.     error("can't unlink %s (%s)", linkname, strerror(errno));
  196.  
  197.     /* (re)create the new link to newlib */
  198.     if (symlink(newlib, linkname))
  199.     error("can't create link to %s (%s)", newlib, strerror(errno));
  200.  
  201.     /* that's all folks */
  202.     exit(0);
  203. }
  204.